3.3.3 处理器函数

上一小节对处理器进行了介绍,那么什么是处理器函数呢?处理器函数实际上就是与处理器拥有相同行为的函数:这些函数与 ServeHTTP 方法拥有相同的签名,也就是说,它们接受 ResponseWriter 和指向 Request 结构的指针作为参数。代码清单3-8展示了如何在服务器中使用处理器函数。

代码清单3-8 使用处理器函数处理请求

package main
import (
  "fmt"
  "net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello!")
}
func world(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "World!")
}
func main() {
  server := http.Server{
    Addr: "127.0.0.1:8080",
  }
  http.HandleFunc("/hello", hello)
  http.HandleFunc("/world", world)
  server.ListenAndServe()
}

处理器函数的实现原理是这样的:Go语言拥有一种 HandlerFunc 函数类型,它可以把一个带有正确签名的函数 f 转换成一个带有方法 fHandler 。比如说,对下面这个 hello 函数来说:

func hello(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintf(w, "Hello!")
}

程序只需要执行以下代码:

helloHandler := HandlerFunc(hello)

就可以把 helloHandler 设置成一个 Handler 。如果你对此感到疑惑,那么不妨回顾一下之前展示过的接受处理器的服务器代码:

type MyHandler struct{}
func (h *MyHandler) ServeHTTP (w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello World!")
}
func main() {
    handler := MyHandler{}
    server := http.Server{
        Addr: "127.0.0.1:8080",
        Handler: &handler,
    }
    server.ListenAndServe()
}

这个程序使用了以下这行代码来绑定URL地址 /hellohello 函数:

http.Handle("/hello", &hello)

这行代码向我们展示了 Handle 函数将一个处理器绑定至URL的具体方法。此外,在接受处理器函数的代码清单3-8中, HandleFunc 函数会将 hello 函数转换成一个 Handler ,并将它与 DefaultServeMux 进行绑定,以此来简化创建并绑定 Handler 的工作。换句话说,处理器函数只不过是创建处理器的一种便利的方法而已。代码清单3-9展示了 http.HandleFunc 函数的具体定义。

代码清单3-9  http.HandleFunc 函数的源代码

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
   DefaultServeMux.HandleFunc(pattern, handler)
}

而下面是 ServeMux.HandleFunc 方法的定义:

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter,
   *Request)) {
  mux.Handle(pattern, HandlerFunc(handler))
}

注意这个方法是如何使用 HandlerFunc 函数将传入的 handler 函数转换成真正的处理器的。

虽然处理器函数能够完成跟处理器一样的工作,并且使用处理器函数的代码比使用处理器的代码更为整洁,但是处理器函数并不能完全代替处理器。这是因为在某些情况下,代码可能已经包含了某个接口或者某种类型,这时我们只需要为它们添加 ServeHTTP 方法就可以将它们转变为处理器了,并且这种转变也有助于构建出更为模块化的Web应用。

results matching ""

    No results matching ""